package org.jeecg.modules.oms.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.oms.mapper.FinanceStatisticsMapper;
import org.jeecg.modules.oms.service.IFinanceStatisticsService;
import org.jeecg.modules.oms.vo.FinanceStatisticsVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jeecg.common.util.oConvertUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 财务统计服务实现类 - 应收应付模块
 * @Author: jeecg-boot
 * @Date: 2025-01-13
 * @Version: V1.0
 */
@Slf4j
@Service
public class FinanceStatisticsServiceImpl implements IFinanceStatisticsService {

    @Autowired
    private FinanceStatisticsMapper financeStatisticsMapper;

    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    // ==================== 应收应付树形结构数据方法实现 ====================

    @Override
    public List<Map<String, Object>> getReceivableTreeData(String startDate, String endDate) {
        try {
            log.info("获取应收账款树形结构数据，开始日期：{}，结束日期：{}", startDate, endDate);
            List<Map<String, Object>> treeData = financeStatisticsMapper.getReceivableTreeData(startDate, endDate);
            log.info("获取到应收账款树形数据 {} 条", treeData.size());
            return treeData;
        } catch (Exception e) {
            log.error("获取应收账款树形结构数据失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    public List<Map<String, Object>> getPayableTreeData(String startDate, String endDate) {
        try {
            log.info("获取应付账款树形结构数据，开始日期：{}，结束日期：{}", startDate, endDate);
            List<Map<String, Object>> treeData = financeStatisticsMapper.getPayableTreeData(startDate, endDate);
            log.info("获取到应付账款树形数据 {} 条", treeData.size());
            return treeData;
        } catch (Exception e) {
            log.error("获取应付账款树形结构数据失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    public Map<String, Object> getReceivablePayableSummary(String startDate, String endDate) {
        try {
            log.info("获取应收应付汇总统计数据，开始日期：{}，结束日期：{}", startDate, endDate);
            Map<String, Object> summary = financeStatisticsMapper.getReceivablePayableSummary(startDate, endDate);
            log.info("获取到应收应付汇总数据：{}", summary);
            return summary != null ? summary : new HashMap<>();
        } catch (Exception e) {
            log.error("获取应收应付汇总统计数据失败", e);
            return new HashMap<>();
        }
    }

    @Override
    public FinanceStatisticsVO.ReceivableOverviewVO getReceivableOverview(String startDate, String endDate) {
        try {
            log.info("获取应收账款概览数据，开始日期：{}，结束日期：{}", startDate, endDate);
            Map<String, Object> summary = financeStatisticsMapper.getReceivablePayableSummary(startDate, endDate);
            
            FinanceStatisticsVO.ReceivableOverviewVO result = new FinanceStatisticsVO.ReceivableOverviewVO();
            if (summary != null) {
                result.setTotalReceivable(getBigDecimalValue(summary, "total_receivable_amount"));
                result.setTotalReceived(getBigDecimalValue(summary, "total_received_amount"));
                result.setTotalUnreceived(getBigDecimalValue(summary, "total_unreceived_amount"));
                
                // 计算回款率
                BigDecimal totalReceivable = result.getTotalReceivable();
                BigDecimal totalReceived = result.getTotalReceived();
                if (totalReceivable != null && totalReceivable.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal receivedRate = totalReceived.divide(totalReceivable, 4, RoundingMode.HALF_UP)
                            .multiply(new BigDecimal("100"));
                    result.setReceivedRate(receivedRate);
                } else {
                    result.setReceivedRate(BigDecimal.ZERO);
                }
            }
            
            return result;
        } catch (Exception e) {
            log.error("获取应收账款概览数据失败", e);
            return new FinanceStatisticsVO.ReceivableOverviewVO();
        }
    }

    @Override
    public FinanceStatisticsVO.PayableOverviewVO getPayableOverview(String startDate, String endDate) {
        try {
            log.info("获取应付账款概览数据，开始日期：{}，结束日期：{}", startDate, endDate);
            Map<String, Object> summary = financeStatisticsMapper.getReceivablePayableSummary(startDate, endDate);
            
            FinanceStatisticsVO.PayableOverviewVO result = new FinanceStatisticsVO.PayableOverviewVO();
            if (summary != null) {
                result.setTotalPayable(getBigDecimalValue(summary, "total_payable_amount"));
                result.setTotalPaid(getBigDecimalValue(summary, "total_paid_amount"));
                result.setTotalUnpaid(getBigDecimalValue(summary, "total_unpaid_amount"));
                
                // 计算付款率
                BigDecimal totalPayable = result.getTotalPayable();
                BigDecimal totalPaid = result.getTotalPaid();
                if (totalPayable != null && totalPayable.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal paidRate = totalPaid.divide(totalPayable, 4, RoundingMode.HALF_UP)
                            .multiply(new BigDecimal("100"));
                    result.setPaidRate(paidRate);
                } else {
                    result.setPaidRate(BigDecimal.ZERO);
                }
            }
            
            return result;
        } catch (Exception e) {
            log.error("获取应付账款概览数据失败", e);
            return new FinanceStatisticsVO.PayableOverviewVO();
        }
    }

    @Override
    public List<Map<String, Object>> getReceivablePayableComparisonData(String startDate, String endDate, String period) {
        try {
            List<Map<String, Object>> data = financeStatisticsMapper.getReceivablePayableComparisonData(startDate, endDate, period);
            return data.stream().map(item -> {
                Map<String, Object> chartItem = new HashMap<>();
                chartItem.put("period", getString(item, "label"));
                chartItem.put("receivable", getBigDecimalValue(item, "receivable"));
                chartItem.put("payable", getBigDecimalValue(item, "payable"));
                return chartItem;
            }).collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取应收应付对比图表数据失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    public List<Map<String, Object>> getAgingAnalysisData(String startDate, String endDate) {
        try {
            List<Map<String, Object>> data = financeStatisticsMapper.getAgingAnalysisData(startDate, endDate);
            return data.stream().map(item -> {
                Map<String, Object> chartItem = new HashMap<>();
                chartItem.put("age_range", getString(item, "ageRange"));
                chartItem.put("amount", getBigDecimalValue(item, "amount"));
                chartItem.put("count", getIntegerValue(item, "count"));
                chartItem.put("percentage", getBigDecimalValue(item, "percentage"));
                return chartItem;
            }).collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取账期分析图表数据失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    public List<FinanceStatisticsVO.LiquidityItem> getLiquidityAnalysis(String startDate, String endDate, String period) {
        try {
            List<Map<String, Object>> data = financeStatisticsMapper.getLiquidityAnalysisData(startDate, endDate, period);
            final BigDecimal[] cumulativeFlow = {BigDecimal.ZERO};
            
            return data.stream().map(item -> {
                FinanceStatisticsVO.LiquidityItem liquidityItem = new FinanceStatisticsVO.LiquidityItem();
                liquidityItem.setDate(parseDate(item.get("date")));
                liquidityItem.setCashInflow(getBigDecimalValue(item, "cashInflow"));
                liquidityItem.setCashOutflow(getBigDecimalValue(item, "cashOutflow"));
                liquidityItem.setNetCashFlow(liquidityItem.getCashInflow().subtract(liquidityItem.getCashOutflow()));
                
                // 计算累计现金流
                BigDecimal netFlow = liquidityItem.getNetCashFlow();
                cumulativeFlow[0] = cumulativeFlow[0].add(netFlow);
                liquidityItem.setCumulativeCashFlow(cumulativeFlow[0]);
                
                return liquidityItem;
            }).collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取资金流动性分析数据失败", e);
            return new ArrayList<>();
        }
    }
    
    @Override
    public void exportReceivablePayableData(String startDate, String endDate, HttpServletResponse response) {
        try (Workbook workbook = new XSSFWorkbook()) {
            // 设置响应头
            String fileName = "应收应付明细_" + (startDate != null ? startDate : "") + "_" + (endDate != null ? endDate : "") + ".xlsx";
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));

            // 获取应收和应付数据
            List<Map<String, Object>> receivableData = this.getReceivableTreeData(startDate, endDate);
            List<Map<String, Object>> payableData = this.getPayableTreeData(startDate, endDate);

            // 创建应收sheet
            createSheet(workbook, "应收账款明细", receivableData, getReceivableHeaders());
            
            // 创建应付sheet
            createSheet(workbook, "应付账款明细", payableData, getPayableHeaders());

            // 写入响应流
            try (OutputStream outputStream = response.getOutputStream()) {
                workbook.write(outputStream);
                outputStream.flush();
            }
        } catch (Exception e) {
            log.error("导出应收应付明细数据失败", e);
            throw new RuntimeException("导出数据失败：" + e.getMessage());
        }
    }
    
    /**
     * 创建Excel Sheet
     */
    private void createSheet(Workbook workbook, String sheetName, List<Map<String, Object>> data, List<String[]> headers) {
        Sheet sheet = workbook.createSheet(sheetName);
        
        // 创建表头
        Row headerRow = sheet.createRow(0);
        for (int i = 0; i < headers.size(); i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers.get(i)[0]);
            // 设置列宽
            sheet.setColumnWidth(i, headers.get(i)[0].getBytes().length * 2 * 256);
        }

        // 填充数据
        if (data != null && !data.isEmpty()) {
            int rowNum = 1;
            for (Map<String, Object> item : data) {
                Row row = sheet.createRow(rowNum++);
                for (int i = 0; i < headers.size(); i++) {
                    String key = headers.get(i)[1];
                    Object value = item.get(key);
                    Cell cell = row.createCell(i);
                    setCellValue(cell, value);
                }
            }
        }
    }

    /**
     * 设置单元格值
     */
    private void setCellValue(Cell cell, Object value) {
        if (value == null) {
            cell.setCellValue("");
        } else if (value instanceof Number) {
            if (value instanceof Integer || value instanceof Long) {
                cell.setCellValue(((Number) value).longValue());
            } else {
                cell.setCellValue(((Number) value).doubleValue());
            }
        } else if (value instanceof Boolean) {
            cell.setCellValue((Boolean) value);
        } else if (value instanceof Date) {
            cell.setCellValue((Date) value);
        } else {
            cell.setCellValue(String.valueOf(value));
        }
    }

    /**
     * 获取应收账款表头
     */
    private List<String[]> getReceivableHeaders() {
        List<String[]> headers = new ArrayList<>();
        headers.add(new String[]{"客户名称", "customerName"});
        headers.add(new String[]{"项目名称", "projectName"});
        headers.add(new String[]{"订单编号", "orderNo"});
        headers.add(new String[]{"订单金额", "orderAmount"});
        headers.add(new String[]{"已收金额", "receivedAmount"});
        headers.add(new String[]{"未收金额", "unreceivedAmount"});
        headers.add(new String[]{"应收日期", "dueDate"});
        headers.add(new String[]{"状态", "status"});
        return headers;
    }

    /**
     * 获取应付账款表头
     */
    private List<String[]> getPayableHeaders() {
        List<String[]> headers = new ArrayList<>();
        headers.add(new String[]{"供应商名称", "supplierName"});
        headers.add(new String[]{"采购单号", "purchaseNo"});
        headers.add(new String[]{"物料名称", "materialName"});
        headers.add(new String[]{"采购金额", "purchaseAmount"});
        headers.add(new String[]{"已付金额", "paidAmount"});
        headers.add(new String[]{"未付金额", "unpaidAmount"});
        headers.add(new String[]{"应付日期", "dueDate"});
        headers.add(new String[]{"状态", "status"});
        return headers;
    }

    // ==================== 工具方法 ====================

    /**
     * 从Map中获取BigDecimal值的辅助方法
     */
    private BigDecimal getBigDecimalValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return BigDecimal.ZERO;
        }
        if (value instanceof BigDecimal) {
            return (BigDecimal) value;
        }
        if (value instanceof Number) {
            return new BigDecimal(value.toString());
        }
        try {
            return new BigDecimal(value.toString());
        } catch (NumberFormatException e) {
            log.warn("无法将值 {} 转换为BigDecimal", value);
            return BigDecimal.ZERO;
        }
    }

    private Integer getIntegerValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return 0;
        }
        if (value instanceof Integer) {
            return (Integer) value;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        try {
            return Integer.parseInt(value.toString());
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    private String getString(Map<String, Object> map, String key) {
        Object value = map.get(key);
        return value != null ? value.toString() : "";
    }

    private Date parseDate(Object dateObj) {
        if (dateObj == null) {
            return new Date();
        }
        if (dateObj instanceof Date) {
            return (Date) dateObj;
        }
        try {
            return dateFormat.parse(dateObj.toString());
        } catch (ParseException e) {
            log.error("日期解析异常", e);
            return new Date();
        }
    }
}
